package org.vectrics.common.util;

import java.util.Iterator;
import java.util.Vector;
import org.apache.log4j.Category;



public abstract class PageList {
    private static Category log = Category.getInstance(PageList.class);
    private boolean endOfList = false;
    private boolean pageRead = false;
    private int pageSize = 10;
    private Vector keys = null;
    private Object currentKey = null;
    private Object nextPageKey = null;
    private Object prevPageKey = null;
    
    
    public Object getNextPageKey() {
        return(nextPageKey);
    }
    
    public Object getPreviousPageKey() {
        return(prevPageKey);
    }
    
    public boolean hasNextPage() {
        if (!pageRead) {
            getPage();
        }
        
        if (getNextPageKey() != null) {
            return(true);
        }
        else {
            return(false);
        }
    }

    
    public boolean hasPreviousPage() {
        if (!pageRead) {
            getPage();
        }
        
        if (getPreviousPageKey() != null) {
            return(true);
        }
        else {
            return(false);
        }
    }
    
    public Vector getKeys() {
        log.debug("getKeys() - called");
        if (keys == null) {
            keys = findKeys();
            
            if (log.isDebugEnabled()) {
                log.debug("getKeys() - for all pages number of total records = " + keys.size());
                Iterator iter = keys.iterator();
                while (iter.hasNext()) {
                    String key = (String)iter.next();
                    log.debug("key: " + key);
                }
            }
        }
        return(keys);
    }


    public boolean getEndOfList() {
        log.debug("getEndOfList() - called");
        return(endOfList);
    }
    
    protected abstract Vector findKeys();
    

    public int getPageSize() {
        return(pageSize);
    }
    
    public void setPageSize(int size) {
        pageSize = size;
    }
    
    protected abstract Vector loadObjects(Vector keyList);

    protected Object getCurrentKey() {
        if (currentKey == null) {
            currentKey = keys.elementAt(0);
        }
        return(currentKey);
    }
    
    public void setCurrentKey(Object key) {
        currentKey = key;
    }

    public Vector getNextPage() {
        if (!pageRead) {
            log.debug("nextPage() - calling getPage() to find location of next pageRead.");
            getPage();
        }
        Vector items = new Vector();        
        if (getNextPageKey() != null) {
            setCurrentKey(getNextPageKey());
            log.debug("nextPage() - getting page elements");
            items.addAll(getPage());
        }
        else {
            if (getKeys().size() > 0) {
                int lastPageIndex = (getKeys().size() - 1) - getPageSize();
                if (lastPageIndex < 0)
                    lastPageIndex = 0;
                Object lastPageKey = getKeys().elementAt(lastPageIndex);
                setCurrentKey(lastPageKey);
            }
            else {
                log.debug("Key list size is zero, ignoring next page request.");
            }
            
            log.warn("nextPage() - this method should not be called if next page does not exist.");
        }
        return(items);
    }


    public Vector getPreviousPage() {
        log.debug("previousPage() - called.  Getting items for previous page.");
        if (!pageRead) {
            log.debug("previousPage() - calling getPage() to find location of next pageRead.");
            getPage();
        }
        Vector items = new Vector();        
        if (getPreviousPageKey() != null) {
            setCurrentKey(getPreviousPageKey());
            log.debug("previousPage() - getting page elements");
            items.addAll(getPage());
        }
        else {
            setCurrentKey(null);
            items.addAll(getPage());
            log.warn("previousPage() - this method should not be called if previous page does not exist.");
        }
        log.debug("previousPage() - done");
        
        return(items);
    }

    
    public Vector getPage() {
        log.debug("getPage() called.");
        
        endOfList = false;
        
        log.debug("getPage() - getting keys.");
        Vector keyList = getKeys();
        Vector objects = new Vector();
        if (keyList.size() > 0) {
            int startIndex = keyList.indexOf(getCurrentKey());
            int endIndex = startIndex + getPageSize();
            int index = startIndex;
            if (endIndex >= keyList.size()) {
                endIndex = keyList.size();
                endOfList = true;
            }
            
            log.debug("getPage() - finding keys for current page.");
            Vector pageKeyList = new Vector();
            while ((index < endIndex) && (index < keyList.size())) {
                log.debug("getPage() - adding key item at: " + index);
                Object key = (Object)keyList.elementAt(index);
                pageKeyList.add(key);
                index++;
            }


            log.debug("getPage() - setting next key (Key for next page)");
            if (index < keyList.size()) {
                nextPageKey = (Object)keyList.elementAt(index);
            }
            else {
                nextPageKey = null;
            }
            
            log.debug("getPage() - setting prev key (Key for top of prev page)");
            if (startIndex > 0) {
                int prevPageIndex = startIndex - getPageSize();
                if (prevPageIndex < 0)
                    prevPageIndex = 0;
                
                if (log.isDebugEnabled())
                    log.debug("getPage() - prevPageIndex = " + prevPageIndex);
                prevPageKey = (Object)keyList.elementAt(prevPageIndex);
            }
            else {
                log.debug("getPage() - prevPageIndex = {No page previous to current page}");
                prevPageKey = null;
            }
            
            log.debug("getPage() - finding objects for the keys of the current page.");
            objects.addAll(loadObjects(pageKeyList));
        }
        log.debug("getPage() - finished.");
        pageRead = true;
        
        return(objects);
    }
    
}    

